package com.cloud.async.business.context;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cloud.async.result.core.factory.AsyncResultFactory;
import com.cloud.async.util.ex.AsyncException;
import com.web.cloud.scala.helper.AsyncFunction;
import org.springframework.util.StringUtils;
import scala.Function0;

import java.util.concurrent.Executor;
import java.util.concurrent.CompletableFuture;

/**
 * @author chengrui
 * @title: AbstractApplicationContext
 * @projectName webCloudAsync
 * @description: 抽象及其相应实现，业务实现核心类
 * @date 2021/9/26 21:49
 */
public abstract class AbstractApplicationContext extends ApplicationContext {

    /**
     * 设置线程池
     */
    private Executor executor;

    /**
     * 结果处理工厂
     */
    private AsyncResultFactory asyncResultFactory;


    /**
     * 全局参数进行设置获取结果的等待时间
     */
    private Long milliSecond = 1000L;


    protected void initializeExecutor(Executor executor) {
        this.executor = executor;
    }

    /**
     * 全局参数进行设置获取结果的等待时间
     */
    protected void initializeMilliSecond(Long milliSecond) {
        this.milliSecond = milliSecond;
    }

    /**
     * 获取参数
     *
     * @return
     */
    protected Long getMilliSecond() {
        return milliSecond;
    }

    /**
     * 设置结果处理
     *
     * @param asyncResultFactory
     */
    protected void initializeAsyncResultFactory(AsyncResultFactory asyncResultFactory) {
        if (!(asyncResultFactory instanceof AsyncResultFactory)) {
            throw new AsyncException("AsyncResultFactory object is not an implementation class.");
        }
        this.asyncResultFactory = asyncResultFactory;
    }

    public AbstractApplicationContext() {
    }

    @Override
    public String doBusiness(Function0 asyncFunction) {
        //获取存放在数据源中的KEY
        String key = IdUtil.randomUUID();
        CompletableFuture<Object> result = AsyncFunction.doBusiness(asyncFunction, this.executor);
        try {
            saveData(key, result);
        } catch (Exception e) {
            throw new AsyncException("Failed to save data to data source.", e);
        }
        return key;
    }

    @Override
    public String doBusiness(Function0<Object> asyncFunction, boolean needReturnValue) {
        try {
            if (needReturnValue) {
                return this.doBusiness(asyncFunction);
            } else {
                AsyncFunction.doBusinessNullResult(asyncFunction, this.executor);
                return "SUCCESS";
            }
        } catch (Exception e) {
            throw new AsyncException("Business execution failed.", e);
        }
    }


    @Override
    public <T> T getResult(Class<T> requiredType, String key) {
        Object result = this.getResult(key);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        return this.asyncResultFactory.createAsyncResult().getResult(requiredType, result);
    }

    @Override
    public <T> T getResult(Class<T> requiredType, String key, Long milliSecond) {
        Object result = this.getResult(key, ObjectUtil.isEmpty(milliSecond) ? getMilliSecond() : milliSecond);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        return this.asyncResultFactory.createAsyncResult().getResult(requiredType, result);
    }

}
